import bytes from "bytes";
import fg from "fast-glob";
import fs from "fs-extra";
import path from "path";
import sharp from "sharp";
import { UnityHelper } from "./UnityHelper.js";
import { toolchain } from "../toolchain.js";

export class NPOT {
    private imgRoots = ['.'];
    public async fixAll(): Promise<void> {
        let minSize = toolchain.opts.minSize ? bytes(toolchain.opts.minSize) : 0;
        if (toolchain.opts.input) {
            await this.fixNPOT(path.join(toolchain.opts.projectRoot, toolchain.opts.input), true);
            return;
        }
        const assetsRoot = path.join(toolchain.opts.projectRoot, 'Assets/AssetSources');
        for (const ir of this.imgRoots) {
            const imgRoot = path.join(assetsRoot, ir);
            const imgs = await fg(['**/*.png', '**/*.jpg'], { cwd: imgRoot, ignore: ['font/**/@**/**/*'] });
            for (const img of imgs) {
                const file = path.join(imgRoot, img);
                const fstat = await fs.stat(file);
                if (minSize > 0) {
                    if (fstat.size < minSize) {
                        continue;
                    }
                }
                if (ir.includes('atlas/') && fstat.size < 51200) {
                    // 图集图片对大尺寸的图进行调整
                    continue;
                }
                await this.fixNPOT(file, false);
            }
        }
    }

    public async fixNPOT(file: string, force: boolean): Promise<void> {
        const s = sharp(file);
        const meta = await s.metadata();
        if (meta.width == null || meta.height == null) {
            console.error('Cannot get width/height:', file);
            return;
        }

        if (!force) {
            if (toolchain.opts.minWh != null && meta.width < toolchain.opts.minWh && meta.height < toolchain.opts.minWh) {
                return;
            }
            if (file.includes('atlas') && meta.width < 2048 && meta.height < 2048) {
                // 图集图片对大尺寸的图进行调整
                return;
            }
        }
        let w = meta.width;
        let h = meta.height;
        // 读入maxTextureSize
        const texture = await UnityHelper.loadMeta(file + '.meta');
        const psMap: { [buildTarget: string]: number } = {};
        for (const ps of texture.TextureImporter.platformSettings) {
            psMap[ps.buildTarget] = ps.maxTextureSize;
        }
        const maxTextureSize = psMap['WebGL'] || psMap['DefaultTexturePlatform'];
        const maxWH = Math.max(meta.width, meta.height);
        // 如果原图尺寸超过maxTextureSize，需先进行缩放
        if (maxWH > maxTextureSize) {
            if (meta.width > meta.height) {
                w = maxTextureSize;
                h = Math.round(maxTextureSize / meta.width * meta.height);
            } else {
                h = maxTextureSize;
                w = Math.round(maxTextureSize / meta.height * meta.width);
            }
        }
        if (w % 4 != 0 || h % 4 != 0) {
            let nw = w % 4 == 0 ? w : (w + 4 - (w % 4));
            let nh = h % 4 == 0 ? h : (h + 4 - (h % 4));
            if (maxWH > maxTextureSize) {
                // 恢复缩放
                if (meta.width > meta.height) {
                    nw = Math.round(nw * meta.width / maxTextureSize);
                    nh = Math.round(nh * meta.width / maxTextureSize);
                } else {
                    nw = Math.round(nw * meta.height / maxTextureSize);
                    nh = Math.round(nh * meta.height / maxTextureSize);
                }
            }
            const tmpSave = 'npot.tmp' + path.extname(file);
            // 注意如果fit设置为contain，默认填充黑色不透明背景，需设置background
            // await s.resize(nw, nh, { fit: 'contain', background: { r: 255, g: 255, b: 255, alpha: 0 } }).toFile(tmpSave);
            await s.resize(nw, nh, { fit: 'fill' }).toFile(tmpSave);
            await fs.copyFile(tmpSave, file);
            await fs.unlink(tmpSave);
            console.log(file, `${meta.width}×${meta.height} -> ${nw}×${nh}`);
        }
    }
}
